--- Test properties of record data types
module tests.qc.Record where

import frege.test.QuickCheck

data Int1 = Int1 { field :: Int }

p_setInt1 = property $ \x -> let d = Int1 { field = x } in d.field == x


--- An alias of @a -> b@ to define @instance Show@
newtype F a b = F (a -> b)
instance Show (F a b) where
  show _ = "<function>"
instance (CoArbitrary a, Arbitrary b) => Arbitrary (F a b) where
  arbitrary = F <$> arbitrary


--- @value'@ will be mangled to @mem$value$tick@. Will this work?
data Mangled a = Mangled { value' :: a }
derive Show (Mangled a)

instance (Arbitrary a) => Arbitrary (Mangled a) where
  arbitrary = do
      value' <- arbitrary
      return Mangled { value' }

-- the next two should fail unless the QC tool mangels names correctly
(°°°) = once true
p_accessMangled' = property $ \(x :: Mangled Int) -> let Mangled a = x in a == x.value'
p_matchMangled  = property $ \(x@Mangled{value'} :: Mangled Int) -> value' == x.value'
p_matchMangledA = property $ \(x@Mangled{value'=a} :: Mangled Int) -> a == x.value'
p_updateMangled = property $ \(b :: Bool) (x :: Mangled Int) -> let y = x.{ value' = b } in y.value' == b
p_changeMangled = property $ \(F f :: F Int Bool) (x :: Mangled Int) -> let y = x.{ value' <- f } in y.value' == f (x.value')


data Mangled3 a b = Mangled3 { value :: a, value' :: b, value'' :: Int }
derive Show (Mangled3 a b)

instance (Arbitrary a, Arbitrary b) => Arbitrary (Mangled3 a b) where
  arbitrary = do
      value <- arbitrary
      value' <- arbitrary
      value'' <- arbitrary
      return Mangled3 { value, value', value'' }

p_accessMangled3 = property $ \(x :: Mangled3 Int Bool) -> let Mangled3 a b c = x in
    a == x.value  &&
    b == x.value' &&
    c == x.value''
p_matchMangled3  = property $ \(x@Mangled3{value, value', value''} :: Mangled3 Long Bool) ->
    value   == x.value  &&
    value'  == x.value' &&
    value'' == x.value''
p_matchMangled3A = property $ \(x@Mangled3{value=a, value'=b, value''=c} :: Mangled3 Char ()) ->
    a == x.value  &&
    b == x.value' &&
    c == x.value''
p_updateMangled3 = property $ \(a :: Int) (b :: Bool) (c :: Int) (x :: Mangled3 Char Long) ->
    let y = x.{ value = a, value' = b, value'' = c } in
    a == y.value  &&
    b == y.value' &&
    c == y.value''
p_changeMangled3 = property $ \(F f :: F Int [Bool]) (F g :: F Char String) (F h :: F Int Int) (x :: Mangled3 Int Char) ->
    let y = x.{ value <- f, value' <- g, value'' <- h } in
    y.value   == f (x.value) &&
    y.value'  == g (x.value') &&
    y.value'' == h (x.value'')
